package c.x.jy.common.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

@SuppressWarnings("all")
public class GetClassinfo {

	protected static Logger logger = LoggerFactory.getLogger(GetClassinfo.class);

	private static final Map<String, String> BASETYPE = new HashMap() {
		{
			put("int", "java.lang.Integer");
			put("byte", "java.lang.Byte");
			put("short", "java.lang.Short");
			put("long", "java.lang.Long");
			put("float", "java.lang.Float");
			put("double", "java.lang.Double");
			put("boolean", "java.lang.Boolean");
			put("char", "java.lang.Char");
		}
	};

	/**
	 * 使用反射根据属性名称获取属性值
	 * 
	 * @param fieldName 属性名称
	 * @param o         操作对象
	 * @return Object 属性值
	 */
	public static Object getFieldValueByName(String fieldName, Object o) {
		Object value = null;
		boolean error = false;
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getter = "get" + firstLetter + fieldName.substring(1);
			Method method = o.getClass().getMethod(getter, new Class[] {});
			value = method.invoke(o, new Object[] {});
			// System.out.println("getter 值" + getter+": "+value);

		} catch (Exception e) {
			// e.printStackTrace();
			error = true;
			logger.info(e.getMessage());

		}

		if (value == null && o instanceof Map)
			try {
				Map map = (Map) o;
				value = map.get(fieldName);
			} catch (Exception e) {
				logger.info(e.getMessage());
				error = true;
			}

		return value;
	}

	/**
	 * @paramo 操作对象
	 * @parammethodName 方法名
	 * @paramattName 属性名
	 * @paramvalue 值
	 * @returnget 方法返回实际值set方法返回操作后对象
	 */
	private static Object Operation(Object o, String methodName, String attName, Class<?>[] paramType,
			Object... value) {
		// 出错标志
		boolean opErr = false;
		Object res = null;
	
		if (o == null)
			return null;
		Method method = null;
		Class<?> type = o.getClass();
		try {

			
			if (paramType == null&&value!=null&&value.length>0) {
				paramType = new Class<?>[value.length]; // paramType == null ? value.getClass() : paramType;
				for (int i = 0; i < value.length; i++) {
					if(value[i]!=null)
					paramType[i] = value[i].getClass();
				}
			}
			if (methodName.indexOf("get") != -1) {
				// get方法
				if (o instanceof Map) {
					Map map = (Map) o;
					return map.get(attName);
				}
				try {
				// 获取方法
				method = type.getDeclaredMethod(methodName, paramType);
				} catch (Exception e) {
					// TODO: handle exception
	 
				}
				if (method == null&&type.getSuperclass()!=null)
					method = type.getSuperclass().getDeclaredMethod(methodName, paramType);
				// 执行
				if(value!=null&&value.length>0) {
					res = 	method.invoke(o, value);
				}else {
					res = 	method.invoke(o);
				}
	 
			} else if (methodName.indexOf("set") != -1) {
				// set方法
				if (o instanceof Map) {
					Map map = (Map) o;
					map.put(attName, value);
					return map;
				}
		 

				try {
					method = type.getDeclaredMethod(methodName, paramType);
				} catch (Exception e) {
				 //	e.printStackTrace();
					if(type.getSuperclass()!=null)
					method = type.getSuperclass().getDeclaredMethod(methodName, paramType);
				}

 
				method.setAccessible(true);
				method.invoke(o, value);
				return o;
			} else {

				if (paramType == null && value != null && value.length > 0) {
					paramType = new Class<?>[value.length]; // paramType == null ? value.getClass() : paramType;
					for (int i = 0; i < value.length; i++) {
						if (value[i] != null)
					 
						paramType[i] = value[i].getClass();
					}
				}
			 
				// System.out.println("paramType:"+JSON.toJSONString(paramType));
				// 当没有传入参数类型时通过value获取参数类型
				// paramType = paramType == null ? value.getClass() : paramType;
				try {
				// 获取方法
				method = type.getDeclaredMethod(attName, paramType);
				} catch (Exception e) {
			 //	e.printStackTrace();
				}
			
				if (method == null&&type.getSuperclass()!=null) 	method = type.getSuperclass().getDeclaredMethod(attName, paramType);
			
      
				// 执行 
				method.setAccessible(true);
				Object result=null;
				if(value!=null&&value.length>0&&value[0]!=null) {
					result=	method.invoke(o, value);
				}else {
					result=	method.invoke(o);
				}
				//System.out.println(result);
			 return result;
			}
		} catch (Exception e) {
			// 通过get/set方法操作属性失败
	
			opErr = true;
			if (opErr) {
				   logger.info("执行对象："+o);
				   logger.info("执行主法："+methodName);
			       logger.info("获取参数名："+attName);
			    	logger.error(":[WARN]直接对属性'" + attName + "进行操作(不借助get/set方法).  ==>"+methodName);
				  e.printStackTrace();
				  if(value!=null)for(Object obj :value) {System.out.println(obj);}
			}
		}

		if (opErr) {
			// 通过打破封装方式直接对值进行操作
			try {
				Field field = null;
				// 获取属性
				field = type.getDeclaredField(attName);
				// 打破封装
				field.setAccessible(true);

				if (methodName.indexOf("get") != -1) {
					// get方法
					// 获取属性值
					res = field.get(o);
				} else if (methodName.indexOf("set") != -1) {

					// set方法
					// 设置属性值
					field.set(o, value);
					res = o;
				}
			} catch (Exception e) {
				// 两种方法都操作失败
				if (opErr) {
					logger.error(":[ERROR]属性'" + attName + "'操作失败.");
				}
			}
		}

		return res;
	}

	/**
	 * 反射执行方法
	 * 
	 * @param o         反射执行对象
	 * @param method    执行方法
	 * @param paramType 参数类型，为空则取值类型
	 * @param value     值数组
	 * @return
	 */
	public static Object invoke(Object o, String method, Class<?>[] paramType, Object... value) {
		return Operation(o, "", method, paramType, value);
	}
	

	/**
	 * 反射执行方法
	 * 
	 * @param o         反射执行对象
	 * @param method    执行方法
	 * @param value     值数组
	 * @return
	 */
	public static Object invoke(Object o, String method,  Object... value) {
		return Operation(o, "", method, null, value);
	}

	/**
	 * 设置属性值
	 *
	 * @paramo 操作对象
	 * @paramattName 属性名
	 * @paramvalue 参数值
	 * @paramparamType 参数类型
	 * @return操作后对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T set(T o, String attName, Object value, Class<?> paramType) {
		if (o == null || attName == null || attName.isEmpty()) {
			return null;
		}
		String methodName = attNameHandle("set", attName);
		Class<?>[] p = new Class<?>[] { paramType };
		  //  setFieldValueByName(   attName,o,new Object[] {value}) ;// (T) Operation(o, methodName, attName, p, value);
			 return (T) Operation(o, methodName, attName, p, value);
		//     return null;
	 
	}

	/**
	 * 获取属性值
	 *
	 * @paramo 操作对象
	 * @paramattName 属性名
	 * @paramreturnType 返回值类型
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T get(Object o, String attName, Class<T> returnType) {
		if (o == null || attName == null || attName.isEmpty()) {
			return null;
		}
		String methodName = attNameHandle("get", attName);

		return (T) Operation(o, methodName, attName, null, null);
	}

	/**
	 * 属性名处理
	 *
	 * @parammethod 方法(get/set)
	 * @paramattName
	 * @return
	 */
	private static String attNameHandle(String method, String attName) {
		StringBuffer res = new StringBuffer(method);
		// 属性只有一个字母
		if (attName.length() == 1) {
			res.append(attName.toUpperCase());
		} else {
			// 属性包含两个字母及以上
			char[] charArray = attName.toCharArray();
			// 当前两个字符为小写时,将首字母转换为大写
			if (Character.isLowerCase(charArray[0]) && Character.isLowerCase(charArray[1])) {
				res.append(Character.toUpperCase(charArray[0]));
				res.append(attName.substring(1));
			} else {
				res.append(attName);
			}
		}

		return res.toString();
	}

	/**
	 * 根据属性名和属性类型设置属性值
	 * 
	 * @param fieldName
	 * @param o         传递对象
	 * @param vals      多个值数组
	 * @return
	 */

	private static boolean setFieldValueByName(String fieldName, Object o, Object[] vals) {
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String setter = "set" + firstLetter + fieldName.substring(1);
			// System.out.println(vals[0].getClass());
			Class[] classs = new Class[vals.length];
			for (int i = 0; i < vals.length; i++) {
				classs[i] = vals[i].getClass();
				// System.out.println(classs[i]);
			}
			Method method = o.getClass().getMethod(setter, classs);
			// System.out.println("method:"+method);
			Object value = method.invoke(o, vals);
			// return value;
			return true;
		} catch (Exception e) {
			// System.out.println(fieldName+"/"+e.getMessage()+"/"+type);
			// e.printStackTrace();
			logger.info("set error:{}", e.getMessage());
			if (o instanceof Map)
				try {
					Map map = (Map) o;
					map.put(fieldName, vals[0]);
				} catch (Exception e1) {
					logger.info(e1.getMessage());
				}
			return false;
		}
	}

	/**
	 * 根据属性名和指定类型设置属性值
	 * 
	 * @param fieldName 属性名
	 * @param o         设置对象
	 * @param types     属性类型
	 * @param valss     属性值
	 * @return
	 */

	private static Object setFieldValueByName(String fieldName, Object o, Class[] types, Object[] vals) {
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String setter = "set" + firstLetter + fieldName.substring(1);
			// System.out.println(vals[0].getClass());
			Method method = o.getClass().getMethod(setter, types);
			Object obj = method.invoke(o, vals);
			return obj;
		} catch (Exception e) {
			logger.info(fieldName + "/" + e.getMessage() + "/" + types);
			// e.printStackTrace();
			return null;
		}
	}

	/**
	 * 获取对象属性名数组
	 */
	private static String[] getFiledName(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		String[] fieldNames = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			// System.out.println(fields[i].getType());
			fieldNames[i] = fields[i].getName();
			// System.out.println(fields[i].getName());
		}
		return fieldNames;
	}

	/**
	 * 获取对象属性类型(type)，属性名(name)，属性值(value)的map组成的list
	 *
	 */

	private static List getFiledsInfo(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		String[] fieldNames = new String[fields.length];
		List<Map> list = new ArrayList<Map>();
		Map<String, Object> infoMap = null;
		for (int i = 0; i < fields.length; i++) {
			infoMap = new HashMap<String, Object>();
			infoMap.put("type", fields[i].getType().toString());
			infoMap.put("name", fields[i].getName());
			infoMap.put("value", getFieldValueByName(fields[i].getName(), o));
			list.add(infoMap);
		}
		return list;
	}

	/**
	 * 获取对象属性类型(type)，属性名(name)的map
	 */

	private static Map getFiledsInfomap(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		// String[] fieldNames = new String[fields.length];
		Map map = new HashMap();
		Map<String, Object> infoMap = null;
		for (int i = 0; i < fields.length; i++) {
			infoMap = new HashMap<String, Object>();
			infoMap.put("type", fields[i].getType());
			infoMap.put("name", fields[i].getName());
			// infoMap.put("value", getFieldValueByName(fields[i].getName(),o));
			map.put(fields[i].getName(), infoMap);
		}
		return map;
	}

	/**
	 * 获取对象的所有属性值，返回一个对象数组
	 */
	private static Object[] getFiledValues(Object o) {
		String[] fieldNames = getFiledName(o);
		Object[] value = new Object[fieldNames.length];
		for (int i = 0; i < fieldNames.length; i++) {
			value[i] = getFieldValueByName(fieldNames[i], o);
		}
		return value;
	}

	/**
	 * 实体对象转MAP
	 * 
	 * @param o
	 * @return
	 */

	public static Map ObjectToMap(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		// String[] fieldNames = new String[fields.length];
		Map<String, Object> infoMap = new HashMap<String, Object>();
		if (fields.length > 0)
			for (int i = 0; i < fields.length; i++) {
				Object obj = getFieldValueByName(fields[i].getName(), o);
				if (obj != null)
					infoMap.put(fields[i].getName(), obj);
			}
		return infoMap;
	}

	/**
	 * map 转实体对象
	 * 
	 * @param <T>
	 * 
	 * @param map
	 * @param o
	 * @return
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	public static <T> T MapToObject(Map map, Class<T> o) {
		T res = null;
		try {
			res = o.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (map == null || map.isEmpty())
			return res;
		Field[] fields = res.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			if (map.containsKey(fields[i].getName())) {
				// System.out.println(fields[i].getName()+"/:"+map.get(fields[i].getName()));
				try {
					setFieldValueByName(fields[i].getName(), res, new Object[] { map.get(fields[i].getName()) });
				} catch (Exception e) {
					logger.info(e.getMessage());
					// e.printStackTrace();
				}
			}
		}
		return res;
	}

	/**
	 * json转实体对象
	 * 
	 * @param map
	 * @param o
	 * @return
	 */

	public static Object JsonChangeObject(JSONObject json1, Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		Map<String, Map> map = getFiledsInfomap(o);
		// Class ownerClass = JSONArray.class;
		JSONObject json = new JSONObject();
		for (Iterator iterator = json1.entrySet().iterator(); iterator.hasNext();) {
			Entry entry = (Entry) iterator.next();
			// if(entry.getValue() TypeInfo of Object ){

			// }
			String key = entry.getKey().toString().replaceAll("-", "").toLowerCase();
			json.put(key, entry.getValue());
		}
		for (int i = 0; i < fields.length; i++) {
			if (!json.containsKey(fields[i].getName().toLowerCase())) {
				Object obj = getjsonValueByName(json.get(fields[i].getName().toLowerCase()),
						(Class) map.get(fields[i].getName()).get("type"));
				setFieldValueByName(fields[i].getName(), o,
						new Class[] { (Class) map.get(fields[i].getName()).get("type") }, new Object[] { obj });
			}
		}

		return o;

	}

	/**
	 * 取对像值转换指定格式
	 * 
	 * @param vals
	 * @param c
	 * @return
	 */
	private static Object getjsonValueByName(Object vals, Class c) {
		System.out.println(vals + "/" + c + c.isPrimitive());
		try {
			if (c == java.util.Date.class) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
				return sdf.parse(vals.toString());
			}
			if (c == String.class) {
				Method method = c.getMethod("valueOf", Object.class);
				return method.invoke(null, new Object[] { vals });
			}
			if (c.isPrimitive()) {
				Class cl = Class.forName(BASETYPE.get(c.getName().toString()));
				Method method = cl.getMethod("valueOf", String.class);
				// System.out.println(cl+"/"+method);
				Object o = method.invoke(null, vals.toString());
				Method method1 = cl.getDeclaredMethod(c.getName() + "Value");

				// System.out.println("zzzzzz:"+c.getName()+"value:"+o.getClass());
				return method1.invoke(o);
			}

			Method method = c.getMethod("valueOf", String.class);
			// System.out.println(method.invoke(null, vals[0].toString()) );
			return method.invoke(null, vals.toString());

		} catch (Exception e) {
			logger.info("obj change error:{}", e.getMessage());
			// System.out.println("obj change error:" + e.getMessage());
			return null;
		}
	}

	/**
	 * jsonObject 转换Map
	 * 
	 * @param json
	 * @return
	 */
	public static Map jsonObjectToMap(JSONObject json) {
		Map map = new HashMap();
		for (Iterator iterator = json.entrySet().iterator(); iterator.hasNext();) {
			Entry obj = (Entry) iterator.next();
			map.put(obj.getKey(), obj.getValue());
		}
		return map;
	}

	/**
	 * Map杞琷sonObject
	 * 
	 * @param map
	 * @return
	 */
	public static JSONObject mapTojsonObject(Map map) {
		JSONObject json = new JSONObject();
		for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
			Entry obj = (Entry) iterator.next();
			json.put(obj.getKey().toString(), obj.getValue());
		}
		return json;
	}

	/**
	 * 实体对象转Json
	 * 
	 * @param o
	 * @return
	 */
	public static JSONObject ObjectToJsonObject(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		// String[] fieldNames = new String[fields.length];
		JSONObject infoMap = new JSONObject();
		for (int i = 0; i < fields.length; i++) {
			if (getFieldValueByName(fields[i].getName(), o) != null)
				infoMap.put(fields[i].getName(), getFieldValueByName(fields[i].getName(), o));
		}
		return infoMap;
	}

	/**
	 * 对象属性克隆设置
	 * 
	 * @param originalObj 源对象
	 * @param toObj       目标对象
	 * @return true 成功 false 失败
	 */
	public static boolean ObjectChangeToObject(Object originalObj, Object toObj) {
		if (originalObj == null || toObj == null)
			return false;
		boolean res = false;

		Field[] fields = originalObj.getClass().getDeclaredFields();

		for (Field field : fields) {
			field.setAccessible(true);
			Object ofiled = getFieldValueByName(field.getName(), originalObj);
			if (ofiled != null) {
				try {
					set(toObj, field.getName(), ofiled, ofiled.getClass());
					res = true;
				} catch (Throwable e) {
					e.printStackTrace();
				}

			}
		}

		return res;

	}

	public static void main(String[] args) throws InstantiationException, IllegalAccessException {

	}

	public static <T> List<T> ListhangeToList(List<?> records, Class<T> class1) {
		// System.out.println(JSON.toJSONString(records));
		List<T> list = new ArrayList<>();
		for (int i = 0; i < records.size(); i++) {
			// System.out.println(JSON.toJSONString(list));
			T t = null;
			try {
				t = class1.newInstance();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			ObjectChangeToObject(records.get(i), t);
			list.add(t);
		}
		return list;
	}

}
